package com.stony.orc;

import com.google.common.base.Splitter;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import rx.Observable;
import rx.functions.Action0;
import rx.functions.Action1;
import rx.functions.Func1;
import rx.schedulers.Schedulers;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.logging.SimpleFormatter;

/**
 * <p>orcTest
 * <p>com.stony.orc
 *
 * @author stony
 * @version 上午10:06
 * @since 2017/12/1
 */
public class TonicService extends HttpService {
    private static final Logger logger = LoggerFactory.getLogger(TonicService.class);
    static final String URL_TEMPLATE = "http://www.18ladys.com/cyzy/index.asp?page=%d";
    static final int URL_MAX_PAGE = 21;
    static Store store = Store.newStore();
    static final Cache<String, TonicPageRecord> PAGE_CACHE = CacheBuilder.newBuilder()
            .expireAfterWrite(60, TimeUnit.MINUTES)
            .build();
    static final SimpleDateFormat ISO_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");


    public static void main(String[] args) throws IOException {
//        List<String> errorPage = new ArrayList<String>(16);
        TonicService tonicService = new TonicService();
        tonicService.startup();

    }
    public void startup(){
        logger.info("开始运行 : {}", ISO_FORMAT.format(new Date()));
        CountDownLatch latch = new CountDownLatch(1);
        Observable.range(1, URL_MAX_PAGE)
                .observeOn(Schedulers.immediate())
                .subscribeOn(Schedulers.computation())
                .map(page -> String.format(URL_TEMPLATE, page))
                .retry(1)
                .subscribe(url -> {
                        subscribePages(url, process(url));
                    }, throwable -> {
                        logger.error("页面异常");
                        latch.countDown();
                    }, () -> {
                        logger.info("分页完成.....");
                        latch.countDown();
                    }
                );
        try {
            latch.await();
        } catch (InterruptedException e) {
            logger.warn("解析page等待异常:{}", e.getMessage());
        }
    }
    private void subscribePages(String url, List<TonicPage> pages) {
        logger.info("开始解析page[{}]明细, 大小:{}.", url, pages.size());
        CountDownLatch latch = new CountDownLatch(1);
        Observable<TonicPage> observable = Observable.from(pages);
        observable
//                .subscribeOn(Schedulers.io())
                .map(TonicPage::toTonicPageRecord)
                .doOnNext(page -> {
                    //save page to db
                    store.saveTonicPageRecord(page);
                    PAGE_CACHE.put(page.getTonicUrl(), page);
                })
                .filter(page -> {
                    TonicPageRecord pageRecord = PAGE_CACHE.getIfPresent(page.getTonicUrl());
                    return pageRecord == null || pageRecord.getStatus() == 0;
                })
                .retry(1)
                .subscribe(page -> {
                    try {
                        TonicDetail tonicDetail = process(page);
                        if (store.saveTonicDetail(tonicDetail) > 1L) {
                            TonicPageRecord pageRecord = PAGE_CACHE.getIfPresent(page.getTonicUrl());
                            if(pageRecord != null) {
                                pageRecord.setStatus(1);
                                store.updateTonicPageRecord(pageRecord);
                                PAGE_CACHE.put(pageRecord.getTonicUrl(), pageRecord);
                            }
                        }
                    } catch (IOException e) {
                        logger.error(("process TonicPage[" + page + "]页面异常:"), e);
                    } finally {
                        store.releaseConnection();
                    }
                }, throwable -> {
                    logger.error("分析TonicPage页面异常 : ", throwable);
                    latch.countDown();
                }, () -> {
                    logger.info("分析TonicPage完成 : {}", pages.size());
                    latch.countDown();
                });
        try {
            latch.await();
        } catch (InterruptedException e) {
            logger.warn("解析page详情等待异常:{}", e.getMessage());
        }
    }
    private List<TonicPage> process(String url) {
        logger.info("开始解析TonicPage页面:{}", url);
        Document doc = null;
        List<TonicPage> list = new ArrayList<>();
        try {
            doc = Jsoup.connect(url).timeout(38000).get();
            Elements elements = doc.select(".tb1 li>a");
            for (Element element : elements) {
                logger.info(element.text() + ":" + element.absUrl("href"));
                list.add(new TonicPage(element.text(), element.absUrl("href")));
            }
        } catch (IOException e) {
           logger.error("解析 url="+url+" 异常 : \n", e);
        }
        return list;
    }
    private TonicDetail process(TonicPageRecord tonicPageRecord) throws IOException {
        logger.info("开始解析TonicDetail{}页面:{}", tonicPageRecord.getTonicName(), tonicPageRecord.tonicUrl);
        Document doc = Jsoup.connect(tonicPageRecord.getTonicUrl()).timeout(38000).get();
        Elements es = doc.select(".wq p");
//        System.out.println(es.text());
//        System.out.println("------>>>");
//        System.out.println();
        Iterable<String> it = Splitter.on("<br>").trimResults().split(es.html());
        TonicDetailWords words = new TonicDetailWords();
        for(String s: it) {
            if(ImageUtils.isNotEmpty(s)) {
                words.process(s);
            }
        }
        TonicDetail tonicDetail = JsonUtils.str2Obj(JsonUtils.obj2Str(words.getKeyWords()), TonicDetail.class);
        tonicDetail.setTonicName(tonicPageRecord.getTonicName());
        return tonicDetail;
    }
    static class TonicPage {
        String name;
        String url;
        public TonicPage(String name, String url) {
            this.name = name;
            this.url = url;
        }
        TonicPageRecord toTonicPageRecord() {
            return new TonicPageRecord(name, url);
        }
    }

}
